package com.zy.utils

import android.animation.*
import kotlin.jvm.JvmOverloads
import android.view.animation.LinearInterpolator
import android.animation.ValueAnimator.AnimatorUpdateListener
import android.graphics.Rect
import android.view.View
import java.util.ArrayList

object AnimatorUtils {
    //translationX
    //translationY
    //scaleX
    //scaleY
    //rotationX
    //rotationY
    //rotation
    //alpha
    private const val D = 500
    @JvmOverloads
    fun reset(origin: View?, listener: AnimationListener? = null) {
        if (origin == null) {
            return
        }
        val list: MutableList<Animator> = ArrayList()
        list.add(ObjectAnimator.ofFloat(origin, "scaleX", origin.scaleX, 1f))
        list.add(ObjectAnimator.ofFloat(origin, "scaleY", origin.scaleY, 1f))
        list.add(ObjectAnimator.ofFloat(origin, "translationX", origin.translationX, 0f))
        list.add(ObjectAnimator.ofFloat(origin, "translationY", origin.translationY, 0f))
        list.add(ObjectAnimator.ofFloat(origin, "rotation", origin.rotation, 0f))
        togetherStart(list, listener)
    }

    @JvmStatic
    fun getReset(origin: View): Animator {
        val list: MutableList<Animator> = ArrayList()
        list.add(ObjectAnimator.ofFloat(origin, "scaleX", origin.scaleX, 1f))
        list.add(ObjectAnimator.ofFloat(origin, "scaleY", origin.scaleY, 1f))
        list.add(ObjectAnimator.ofFloat(origin, "translationX", origin.translationX, 0f))
        list.add(ObjectAnimator.ofFloat(origin, "translationY", origin.translationY, 0f))
        list.add(ObjectAnimator.ofFloat(origin, "rotation", origin.rotation, 0f))
        return getTogetherStart(list)
    }

    @JvmOverloads
    fun shake(origin: View?, listener: AnimationListener? = null) {
        if (origin == null) {
            return
        }
        val list: MutableList<Animator> = ArrayList()
        val curScaleX = origin.scaleX
        val curScaleY = origin.scaleY
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "scaleX",
                curScaleX,
                curScaleX * 1.1f,
                curScaleX * 0.9f,
                curScaleX
            )
        )
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "scaleY",
                curScaleY,
                curScaleY * 1.1f,
                curScaleY * 0.9f,
                curScaleY
            )
        )
        togetherStart(list, D, listener)
    }

    fun getShakeAnimator(origin: View): Animator {
        val list: MutableList<Animator> = ArrayList()
        val curScaleX = origin.scaleX
        val curScaleY = origin.scaleY
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "scaleX",
                curScaleX,
                curScaleX * 1.1f,
                curScaleX * 0.9f,
                curScaleX
            )
        )
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "scaleY",
                curScaleY,
                curScaleY * 1.1f,
                curScaleY * 0.9f,
                curScaleY
            )
        )
        return getTogetherStart(list)
    }

    fun getGlobalVisibleRect(origin: View?): Rect {
        val r = Rect()
        if (origin == null) {
            return r
        }
        origin.getGlobalVisibleRect(r)
        return r
    }

    fun getAlpha(origin: View?, show: Boolean): Animator {
        val list: MutableList<Animator> = ArrayList()
        if (show) {
            list.add(ObjectAnimator.ofFloat(origin, "alpha", 0f, 1f, 1f, 1f))
        } else {
            list.add(ObjectAnimator.ofFloat(origin, "alpha", 1f, 1f, 1f, 0f))
        }
        return getTogetherStart(list)
    }

    fun getMove(origin: View, target: View?): Animator {
        return getMove(origin, getGlobalVisibleRect(target))
    }

    fun getMove(origin: View, targetR: Rect): Animator {
        val originR = getGlobalVisibleRect(origin)
        var curScaleX = origin.scaleX
        if (curScaleX == 0f) {
            curScaleX = 1f
        }
        var curScaleY = origin.scaleY
        if (curScaleY == 0f) {
            curScaleY = 1f
        }
        val originWidth = originR.width() / curScaleX
        val originHeight = originR.height() / curScaleY
        val targetWidth = targetR.width()
        val targetHeight = targetR.height()

        //缩放动画
        val list: MutableList<Animator> = ArrayList()
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "scaleX",
                curScaleX,
                targetWidth.toFloat() / originWidth
            )
        )
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "scaleY",
                curScaleY,
                targetHeight.toFloat() / originHeight
            )
        )
        val originXCenter = originR.centerX()
        val originYCenter = originR.centerY()
        val targetXCenter = targetR.centerX()
        val targetYCenter = targetR.centerY()
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "translationX",
                origin.translationX,
                origin.translationX + (targetXCenter - originXCenter)
            )
        )
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "translationY",
                origin.translationY,
                origin.translationY + (targetYCenter - originYCenter)
            )
        )

        //平移-中心点
        return getTogetherStart(list)
    }

    fun move(origin: View?, target: View?) {
        move(origin, getGlobalVisibleRect(target), null)
    }

    fun move(origin: View?, target: Rect?) {
        move(origin, target, null)
    }

    fun move(origin: View?, target: View?, listener: AnimationListener?) {
        move(origin, getGlobalVisibleRect(target), listener)
    }

    fun move(origin: View?, targetR: Rect?, listener: AnimationListener?) {
        if (origin == null || targetR == null) {
            return
        }
        val originR = getGlobalVisibleRect(origin)
        var curScaleX = origin.scaleX
        if (curScaleX == 0f) {
            curScaleX = 1f
        }
        var curScaleY = origin.scaleY
        if (curScaleY == 0f) {
            curScaleY = 1f
        }
        val originWidth = originR.width() / curScaleX
        val originHeight = originR.height() / curScaleY
        val targetWidth = targetR.width()
        val targetHeight = targetR.height()

        //缩放动画
        val list: MutableList<Animator> = ArrayList()
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "scaleX",
                curScaleX,
                targetWidth.toFloat() / originWidth
            )
        )
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "scaleY",
                curScaleY,
                targetHeight.toFloat() / originHeight
            )
        )
        val originXCenter = originR.centerX()
        val originYCenter = originR.centerY()
        val targetXCenter = targetR.centerX()
        val targetYCenter = targetR.centerY()
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "translationX",
                origin.translationX,
                origin.translationX + (targetXCenter - originXCenter)
            )
        )
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "translationY",
                origin.translationY,
                origin.translationY + (targetYCenter - originYCenter)
            )
        )

        //平移-中心点
        togetherStart(list, listener)
    }

    //水平方向上的交换
    fun moveArc(origin: View, target: View?, up: Boolean): Animator {
        return moveArc(origin, getGlobalVisibleRect(target), true)
    }

    fun moveArc(origin: View, targetR: Rect, up: Boolean): Animator {
        val originR = getGlobalVisibleRect(origin)

        //缩放动画
        val list: MutableList<Animator> = ArrayList()
        val originXCenter = originR.centerX()
        val targetXCenter = targetR.centerX()
        list.add(
            ObjectAnimator.ofFloat(
                origin,
                "translationX",
                origin.translationX,
                origin.translationX + (targetXCenter - originXCenter)
            )
        )
        val upDown = ValueAnimator.ofFloat(0f, if (up) 200F else -200F, 0f)
        upDown.interpolator = LinearInterpolator()
        upDown.addUpdateListener { animation ->
            val translationY = animation.animatedValue as Float
            origin.translationY = translationY
        }
        list.add(upDown)

        //平移-中心点
        return getTogetherStart(list)
    }

    fun getTogetherStart(vararg animators: Animator?): Animator {
        val animatorSet = AnimatorSet()
        //同时动画
        animatorSet.playTogether(*animators)
        return animatorSet
    }

    @JvmStatic
    fun getTogetherStart(list: List<Animator>?): Animator {
        val animatorSet = AnimatorSet()
        //同时动画
        animatorSet.playTogether(list)
        animatorSet.duration = D.toLong()
        return animatorSet
    }

    fun getPlaySequentially(vararg animators: Animator?): Animator {
        val animatorSet = AnimatorSet()
        //同时动画
        animatorSet.playSequentially(*animators)
        return animatorSet
    }

    fun getPlaySequentially(list: List<Animator?>?): Animator {
        val animatorSet = AnimatorSet()
        //同时动画
        animatorSet.playSequentially(list)
        return animatorSet
    }

    @JvmOverloads
    fun togetherStart(list: List<Animator>?, listener: AnimationListener? = null) {
        togetherStart(list, D, listener)
    }

    fun togetherStart(list: List<Animator>?, duration: Int, listener: AnimationListener?) {
        val animatorSet = AnimatorSet()
        //同时动画
        animatorSet.playTogether(list)
        animatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator, isReverse: Boolean) {
                super.onAnimationStart(animation, isReverse)
                listener?.onAnimationStart()
            }

            override fun onAnimationEnd(animation: Animator, isReverse: Boolean) {
                super.onAnimationEnd(animation, isReverse)
                listener?.onAnimationEnd()
            }
        })
        animatorSet.duration = duration.toLong()
        animatorSet.start()
    }

    fun startEnterAnimation(
        enterView: View,
        contextView: View,
        heightPixels: Float,
        animationListener: AnimationListener
    ) {
        val animatorList: MutableList<Animator> = ArrayList()
        val shakes = floatArrayOf(1f, 1.05f, 1f, 0.95f, 1f, 1.05f, 1f)
        val shakeList: MutableList<Animator> = ArrayList()
        shakeList.add(ObjectAnimator.ofFloat(enterView, "scaleX", *shakes))
        shakeList.add(ObjectAnimator.ofFloat(enterView, "scaleY", *shakes))
        val shakeAnimatorSet = AnimatorSet()
        shakeAnimatorSet.playTogether(shakeList)
        shakeAnimatorSet.duration = D.toLong()
        animatorList.add(shakeAnimatorSet)

        //平移
        val translationList: MutableList<Animator> = ArrayList()
        translationList.add(ObjectAnimator.ofFloat(enterView, "translationY", 0f, -400f))
        translationList.add(ObjectAnimator.ofFloat(enterView, "alpha", 1f, 0f))
        translationList.add(ObjectAnimator.ofFloat(contextView, "translationY", heightPixels, 0f))
        translationList.add(ObjectAnimator.ofFloat(contextView, "alpha", 0f, 1f))
        val translation = AnimatorSet()
        translation.playTogether(translationList)
        translation.duration = D.toLong()
        animatorList.add(translation)
        val animatorSet = AnimatorSet()
        animatorSet.playSequentially(animatorList)
        animatorSet.duration = D.toLong()
        animatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator) {
                super.onAnimationStart(animation)
                contextView.visibility = View.VISIBLE
                contextView.translationY = heightPixels
            }

            override fun onAnimationEnd(animation: Animator, isReverse: Boolean) {
                super.onAnimationEnd(animation, isReverse)
                enterView.visibility = View.GONE
                animationListener.onAnimationEnd()
            }
        })
        animatorSet.start()
    }

    class AnimationListener {
        fun onAnimationStart() {}
        fun onAnimationEnd() {}
    }
}